<?php

namespace addons\aliocr\library;

use think\Config;

/**
 * 阿里OCR文字识别
 *
 * 错误码文档：https://help.aliyun.com/document_detail/95605.html
 */
class Aliocr
{
    protected $config = [];
    public $data = [];
    public $error = '';

    // 身份证识别接口 https://market.aliyun.com/products/57124001/cmapi010401.html
    protected $apiIdcard = 'https://cardnumber.market.alicloudapi.com/rest/160601/ocr/ocr_idcard.json';
    // 银行卡识别接口 https://market.aliyun.com/products/57124001/cmapi016870.html
    protected $apiBankcard = 'https://yhk.market.alicloudapi.com/rest/160601/ocr/ocr_bank_card.json';
    // 车牌识别接口 https://market.aliyun.com/products/57124001/cmapi020094.html
    protected $apiVehicleplate = 'https://ocrcp.market.alicloudapi.com/rest/160601/ocr/ocr_vehicle_plate.json';
    // 驾驶证识别接口 https://market.aliyun.com/products/57002002/cmapi010402.html
    protected $apiDriverlicense = 'https://cardriving.market.alicloudapi.com/rest/160601/ocr/ocr_driver_license.json';
    // 营业执照识别接口 https://market.aliyun.com/products/57124001/cmapi013592.html
    protected $apiBusinesslicense = 'https://bizlicense.market.alicloudapi.com/rest/160601/ocr/ocr_business_license.json';
    // 名片识别接口 https://market.aliyun.com/products/57124001/cmapi013591.html
    protected $apiBusinesscard = 'https://bizcard.market.alicloudapi.com/rest/160601/ocr/ocr_business_card.json';
    // 通用文字识别接口 https://market.aliyun.com/products/57124001/cmapi020020.html
    protected $apiDocument = 'https://tysbgpu.market.alicloudapi.com/api/predict/ocr_general';
    // protected $apiDocument = 'https://gjbsb.market.alicloudapi.com/ocrservice/advanced';

    public function __construct()
    {
        $this->config = get_addon_config('aliocr');
    }

    /**
     * 识别身份证
     * @param $file
     * @param string $side face=正面|back=反面
     * @return bool
     */
    public function ocrIdcard($file, $side = 'face')
    {
        $apiUrl = $this->apiIdcard;
        $result = $this->ocrByFile($apiUrl, $file, array('side'=> $side));
        return $result;
    }

    /**
     * 银行卡识别
     * @param $file
     * @return bool
     * 注：识别失败时，card_num为空字符串
     */
    public function ocrBankcard($file)
    {
        $apiUrl = $this->apiBankcard;
        $result = $this->ocrByFile($apiUrl, $file);
        return $result;
    }

    /**
     * 车牌识别
     * @param $file
     * @param bool $multiCrop 是否多样本预测
     * @return bool
     */
    public function ocrVehicleplate($file, $multiCrop = false)
    {
        $apiUrl = $this->apiVehicleplate;
        $result = $this->ocrByFile($apiUrl, $file, array('multi_crop'=> $multiCrop));
        return $result;
    }

    /**
     * 驾驶证识别
     * @param $file
     * @param string $side face=首页|back=副页
     * @return bool
     * 注：未能识别项返回 "NoResult" 或 "InvalidInput"
     */
    public function ocrDriverlicense($file, $side = 'face')
    {
        $apiUrl = $this->apiDriverlicense;
        $result = $this->ocrByFile($apiUrl, $file, array('side'=> $side));
        return $result;
    }

    /**
     * 营业执照识别
     * @param $file
     * @return bool
     * 注：未能识别项返回 "FailInRecognition"
     */
    public function ocrBusinesslicense($file)
    {
        $apiUrl = $this->apiBusinesslicense;
        $result = $this->ocrByFile($apiUrl, $file);
        return $result;
    }

    /**
     * 名片识别
     * @param $file
     * @return bool
     * 注：未能识别项返回空数组
     */
    public function ocrBusinesscard($file)
    {
        $apiUrl = $this->apiBusinesscard;
        $result = $this->ocrByFile($apiUrl, $file);
        return $result;
    }

    /**
     * 通用文字识别
     * @param $file
     * @param bool $prob 是否需要识别置信度
     * @return bool
     */
    public function ocrDocument($file, $prob = false)
    {
        $body = array('prob'=> $prob);
        $apiUrl = $this->apiDocument;
        $result = $this->ocrByFile($apiUrl, $file, $body);

        if ($result === true && isset($this->data['ret'])) {
            // 组合文字
            $this->data['words'] = array_column($this->data['ret'], 'word');
            $this->data['content'] = implode('', $this->data['words']);
            return true;
        } else {
            return false;
        }
    }

    /**
     * 指定本地文件路径或网络url来识别
     * @param $apiUrl
     * @param $file 网络图片的url|本地图片的绝对路径
     * @param array $configure
     * @return bool
     */
    public function ocrByFile($apiUrl, $file, $configure = array())
    {
        if ($this->isImageExist($file) === false) {
            $this->error = '图片文件不存在或无法读取：' . $file;
            return false;
        }

        // 本地图片，转base64
        if (strpos($file, 'http') !== 0) {
            $file = base64_encode(file_get_contents($file));
        }

        return $this->ocrCommon($apiUrl, $file, $configure);
    }

    /**
     * 对接阿里云市场ocr各种服务的通用接口
     * @param $apiUrl
     * @param $image 图片的base64编码|网络图片的url
     * @param array $configure
     * @return bool
     */
    public function ocrCommon($apiUrl, $image, $configure = array())
    {
        $params = array('image'=> $image);
        if (count($configure) > 0) {
            $params['configure'] = json_encode($configure);
        }
        $body = json_encode($params);
        $result = $this->_curl($apiUrl, $body);
        return $result;
    }

    private function _curl($url, $body)
    {
        $appCode = $this->config['AppCode'];
        if (!$appCode) {
            $this->error = '未填写AppCode';
            return false;
        }

        $headers = array(
            "Authorization:APPCODE $appCode",
            "Content-Type:application/json; charset=UTF-8"
        );

        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
        curl_setopt($curl, CURLOPT_HEADER, true);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $body);
        curl_setopt($curl, CURLOPT_FAILONERROR, false);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        $curlResult = curl_exec($curl);
        $curlInfo = curl_getinfo($curl);
        curl_close($curl);
        $httpCode = $curlInfo['http_code'];
        if ($httpCode == 200) {
            // 识别成功
            $msg = substr($curlResult, $curlInfo['header_size']);
            $this->data = json_decode($msg, true);
            return true;
        } else {
            // 识别失败
            if (!$curlResult) {
                $this->error = $httpCode;
            } else {
                $this->error = $curlResult;
            }
            return false;
        }
    }

    /**
     * 指定图片是否存在
     * @param $file
     * @return bool
     */
    public function isImageExist($file)
    {
        if (strpos($file, 'http') === 0) {
            // 远程图片url
            $headers = @get_headers($file, 1);
            if (($headers === false) || (strpos($headers[0], '200') === false)) {
                return false;
            }
        } else {
            // 本地图片路径
            if (!is_file($file)) {
                return false;
            }
        }
        return true;
    }
}
